home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Info-Mac 4
/
Info_Mac IV CD-ROM (Pacific HiTech Inc.)(August 1994).iso
/
Development
/
Source
/
tarsrc Folder
/
buffer.c
next >
Wrap
Text File
|
1993-11-27
|
10KB
|
448 lines
/*
* Macintosh Tar
*
* Modified by Craig Ruff for use on the Macintosh.
*/
/*
* Buffer management for public domain tar.
*
* Written by John Gilmore, ihnp4!hoptoad!gnu, on 25 August 1985.
*
* @(#) buffer.c 1.14 10/28/86 Public Domain - gnu
*
*/
#include "tar.h"
#include <Devices.h>
extern OSErr TapeOpen(Boolean noRwd, Boolean rdOnly);
extern int TapeRead(Ptr buf, int len);
extern int TapeWrite(Ptr buf, int len);
extern void TapeClose(void);
Boolean FlushArchive();
union record *arBlock; /* Start of block of archive */
union record *arRecord; /* Current record of archive */
union record *arLast; /* Last+1 record of archive block */
char arReading; /* 0 writing, !0 reading archive */
short archive;
HParamBlockRec apb; /* Archive file PB */
/*
* The record pointed to by save_rec should not be overlaid
* when reading in a new tape block. Copy it to record_save_area first, and
* change the pointer in *save_rec to point to record_save_area.
* Saved_recno records the record number at the time of the save.
* This is used by annofile() to print the record number of a file's
* header record.
*/
static union record **saveRec;
static union record recordSaveArea;
static int savedRecno;
/*
* Record number of the start of this block of records
*/
static int baseRec;
/*
* Return the location of the next available input or output record.
*/
union record *
FindRec()
{
if (arRecord == arLast) {
if (FlushArchive())
return((union record *) nil);
if (arRecord == arLast)
return((union record *) nil); /* EOF */
}
return(arRecord);
}
/*
* Indicate that we have used all records up thru the argument.
* (should the arg have an off-by-1? XXX FIXME)
*/
void
UseRec(rec)
union record *rec;
{
while (rec >= arRecord)
arRecord++;
/*
* Do NOT flush the archive here. If we do, the same
* argument to userec() could mean the next record (if the
* input block is exactly one record long), which is not what
* is intended.
*/
if (arRecord > arLast) {
PgmAlert("\pUseRec", "\parRecord > arLast", nil);
return;
}
}
/*
* Return a pointer to the end of the current records buffer.
* All the space between findrec() and endofrecs() is available
* for filling with data, or taking data from.
*/
union record *
EndOfRecs()
{
return(arLast);
}
/*
* Open an archive file. The argument specifies whether we are
* reading or writing.
*/
Boolean
OpenArchive(prompt, read)
char *prompt;
Boolean read;
{
OSErr err;
char *routine = "\pOpenArchive";
Point where;
SFReply reply;
Str255 name;
archive = 0;
baseRec = 0;
memset(&apb, 0, sizeof(apb));
if (pref.floppy) {
/*
* Open the floppy driver.
*/
apb.fileParam.ioCompletion = nil;
apb.fileParam.ioNamePtr = "\p.Sony";
apb.fileParam.ioVRefNum = 0;
apb.fileParam.ioFVersNum = 0;
apb.fileParam.ioDirID = 0;
apb.fileParam.ioFDirIndex = 0;
apb.ioParam.ioPermssn = (read) ? fsRdPerm : fsWrPerm;
apb.ioParam.ioMisc = nil;
if ((err = PBHOpen(&apb, false)) != noErr) {
OSAlert(routine, "\pPBHOpen or PBHCreate", reply.fName, err);
return(true);
}
if ((apb.fileParam.ioVRefNum = DoInsertFloppy()) == 0)
return(true);
} else if (pref.tape) {
/*
* Open the tape driver.
*/
if ((err = TapeOpen(false, read)) != noErr) {
OSAlert(routine, "\pTapeOpen", nil, err);
return(true);
}
} else {
/*
* Put up a standard file dialog asking for the archive file name.
*/
where.h = where.v = 75;
name[0] = 0;
if (read) {
SFGetFile(where, prompt, nil, -1, nil, nil, &reply);
} else {
SFPutFile(where, prompt, name, nil, &reply);
}
if (!reply.good)
return(true);
/*
* Try and open the archive file.
*/
apb.fileParam.ioCompletion = nil;
apb.fileParam.ioNamePtr = reply.fName;
apb.fileParam.ioVRefNum = reply.vRefNum;
apb.fileParam.ioFVersNum = 0;
apb.fileParam.ioDirID = 0;
apb.fileParam.ioFDirIndex = 0;
if (read) {
apb.ioParam.ioPermssn = fsRdPerm;
apb.ioParam.ioMisc = nil;
err = PBHOpen(&apb, false);
} else {
err = PBHCreate(&apb, false);
if ((err == noErr) || (err == dupFNErr)){
if (PBHGetFInfo(&apb, false)) {
OSAlert(routine, "\pPBHGetFInfo", reply.fName,
apb.fileParam.ioResult);
return(true);
}
memcpy(&apb.fileParam.ioFlFndrInfo.fdCreator, "TAR ", 4);
memcpy(&apb.fileParam.ioFlFndrInfo.fdType, "TARF", 4);
apb.fileParam.ioNamePtr = reply.fName;
apb.fileParam.ioDirID = 0;
if (PBHSetFInfo(&apb, false)) {
OSAlert(routine, "\pPBHSetFInfo", reply.fName,
apb.fileParam.ioResult);
return(true);
}
apb.ioParam.ioPermssn = fsWrPerm;
apb.ioParam.ioMisc = nil;
err = PBHOpen(&apb, false);
}
}
if (err != noErr) {
OSAlert(routine, "\pPBHOpen or PBHCreate", reply.fName, err);
return(true);
}
if (!read) {
apb.ioParam.ioMisc = 0;
if ((err = PBSetEOF((ParmBlkPtr) &apb, false)) != noErr) {
OSAlert(routine, "\pPBSetEOF", reply.fName, err);
return(true);
}
}
}
apb.ioParam.ioPosMode = fsFromStart;
apb.ioParam.ioPosOffset = 0;
/*
* Get a block buffer for use later
*/
arBlock = (union record *) NewPtr((Size) pref.blockSize);
if (arBlock == nil) {
OSAlert(routine, "\pNewPtr", "\parBlock", MemError());
if (pref.tape)
TapeClose();
else if (!pref.floppy)
PBClose((ParmBlkPtr) &apb, false);
return(true);
}
arRecord = arBlock;
arLast = arBlock + pref.blocking;
archive = apb.ioParam.ioRefNum;
arReading = read;
if (read) {
arLast = arBlock; /* Set up for 1st block = # 0 */
FlushArchive();
}
return(false);
}
/*
* Remember a union record * as pointing to something that we
* need to keep when reading onward in the file. Only one such
* thing can be remembered at once, and it only works when reading
* an archive.
*/
SaveRec(pointer)
union record **pointer;
{
saveRec = pointer;
savedRecno = baseRec + arRecord - arBlock;
}
/*
* Perform a write to flush the buffer.
*/
Boolean
FlWrite()
{
OSErr err;
if (pref.tape) {
int n;
n = TapeWrite(arBlock->charptr, pref.blockSize);
if (n == pref.blockSize)
return(false);
OSAlert("\pFLWrite", "\pTapeWrite", "\pArchive write", n);
return(true);
}
apb.ioParam.ioBuffer = arBlock->charptr;
apb.ioParam.ioReqCount = pref.blockSize;
err = PBWrite((ParmBlkPtr) &apb, false);
apb.ioParam.ioPosMode = fsAtMark;
if ((err == noErr) && (apb.ioParam.ioActCount == pref.blockSize))
return(false);
if (
(apb.ioParam.ioActCount != pref.blockSize) ||
(err == dskFulErr)
)
DFAlert();
else
OSAlert("\pFLWrite", "\pPBWrite", "\pArchive write", err);
return(true);
}
/*
* Perform a read to flush the buffer.
*/
Boolean
FlRead()
{
OSErr err; /* Result from system call */
int left; /* Bytes left */
char *more; /* Pointer to next byte to read */
char *routine = "\pFlRead";
/*
* If we are about to wipe out a record that
* somebody needs to keep, copy it out to a holding
* area and adjust somebody's pointer to it.
*/
if (saveRec &&
*saveRec >= arRecord &&
*saveRec < arLast) {
recordSaveArea = **saveRec;
*saveRec = &recordSaveArea;
}
if (pref.tape) {
int n;
n = TapeRead(arBlock->charptr, pref.blockSize);
if (n == pref.blockSize)
return(false);
if (n < 0) {
OSAlert("\pReadError", "\pTapeRead", "\pArchive read", err);
return(true);
}
more = arBlock->charptr + n;
left = pref.blockSize - n;
apb.ioParam.ioActCount = n;
} else {
apb.ioParam.ioBuffer = arBlock->charptr;
apb.ioParam.ioReqCount = pref.blockSize;
err = PBRead((ParmBlkPtr) &apb, false);
apb.ioParam.ioPosMode = fsAtMark;
if ((err == noErr) && (apb.ioParam.ioActCount == pref.blockSize))
return(false);
else if ((err != noErr) && (err != eofErr)) {
OSAlert("\pReadError", "\pPBRead", "\pArchive read", err);
return(true);
}
more = arBlock->charptr + apb.ioParam.ioActCount;
left = pref.blockSize - apb.ioParam.ioActCount;
}
again:
if (0 == (((unsigned)left) % RECORDSIZE)) {
/* FIXME, for size=0, multi vol support */
/* On the first block, warn about the problem */
if (!reblock && baseRec == 0) {
char buf[80];
sprintf(&buf[1], "Blocksize = %ld records",
apb.ioParam.ioActCount / (long) RECORDSIZE);
buf[0] = strlen(&buf[1]);
PgmAlert(routine, buf, nil);
}
arLast = arBlock + ((unsigned)(pref.blockSize - left))/RECORDSIZE;
return(false);
}
if (reblock) {
/*
* User warned us about this. Fix up.
*/
if (left > 0) {
if (pref.tape) {
PgmAlert(routine, "\pReblock & tape: barf!", nil);
return(true);
}
apb.ioParam.ioBuffer = more;
apb.ioParam.ioReqCount = left;
err = PBRead((ParmBlkPtr) &apb, false);
if ((err != noErr) && (err != eofErr)) {
OSAlert("\pReadError", "\pPBRead",
"\pArchive read 2", err);
return(true);
}
if ((apb.ioParam.ioActCount == 0) || (err == eofErr)) {
PgmAlert(routine, "\pEof not on block boundary",
nil);
return(true);
}
left -= apb.ioParam.ioActCount;
more += apb.ioParam.ioActCount;
goto again;
}
} else {
PgmAlert(routine, "\pDid not read blocksize bytes", nil);
return(true);
}
}
/*
* Flush the current buffer to/from the archive.
*/
Boolean
FlushArchive()
{
baseRec += arLast - arBlock; /* Keep track of block #s */
arRecord = arBlock; /* Restore pointer to start */
arLast = arBlock + pref.blocking; /* Restore pointer to end */
if (!arReading)
return(FlWrite());
else
return(FlRead());
}
/*
* Close the archive file.
*/
CloseArchive()
{
ParamBlockRec ctlpb;
if (!arReading)
(void) FlushArchive();
DisposPtr((Ptr) arBlock);
if (pref.floppy) {
/* Eject it! */
memset(&ctlpb, 0, sizeof(ctlpb));
ctlpb.cntrlParam.ioCompletion = nil;
ctlpb.cntrlParam.ioVRefNum = apb.ioParam.ioVRefNum;
ctlpb.cntrlParam.ioCRefNum = apb.ioParam.ioRefNum;
ctlpb.cntrlParam.csCode = 7;
(void) PBControl((ParmBlkPtr) &ctlpb, false);
} else if (pref.tape) {
TapeClose();
} else if (archive != 0)
(void) PBClose((ParmBlkPtr) &apb, false);
archive = 0;
}